#pragma once
#ifndef __BITMAP_H
#define __BITMAP_H

#include "srect.h"

/**
 * @note DO NOT mess with the order of the R,G,B,A components, this struct is 
 * specially designed for the bitmap file format
 */
struct RGB_QUAD
{
	/** blue component */
	unsigned char B;
	/** green component */
	unsigned char G;
	/** red component */
	unsigned char R;
	/** alpha component */
	unsigned char A;
	/** the maximum alloable value of an R G B or A component */
	static const unsigned char MAX_COMPONENT_VALUE = 255;

	/** @param a_BGRA 0xBBGGRR, or 0xBBGGRRAA. example: RGB_QUAD(0xffff00) for cyan */
	RGB_QUAD(const int & a_BGRA)
	{
		*((int*)this) = *((int*)&a_BGRA);
	}
	void set(const unsigned int & a_R,
		const unsigned int & a_G,
		const unsigned int & a_B,
		const unsigned int & a_A)
	{
		R = a_R;	G = a_G;	B = a_B;	A = a_A;
	}
	
	RGB_QUAD(const unsigned int & a_R,
		const unsigned int & a_G,
		const unsigned int & a_B,
		const unsigned int & a_A)
	{
		set(a_R, a_G, a_B, a_A);
	}
	RGB_QUAD(){set(0,0,0,0);}
	/** @param a_value 0:blue component, 1:green component, 2:red component, 3:alpha component, default:undefined */
	unsigned char * getValue(const int & a_value)
	{
		return (&B+a_value);
	}
	bool equals(const RGB_QUAD & rgb)
	{
		// TODO check if it is faster to convert as typecasted ints? probably...
		//return R==rgb.R && G==rgb.G && B==rgb.B && A==rgb.A;
		return *((int*)this) == *((int*)&rgb);
	}
};

// TODO inline methods where it makes sense, add resize component, add palette swapping methods
class BitMaP
{
private:
	long getImageOffset() const ;
	long getPaletteOffset() const ;
	long getFileSize() const ;
	BitMaP();
public:
	unsigned char * getData()const{return (unsigned char*)this;}
	static BitMaP * load(const char * a_filename);
	static void unload(BitMaP * a_bmp);
	void release();
	SPoint getDimension() const;
	SRect getArea() const ;
	long getWidth() const ;
	long getHeight() const ;
	RGB_QUAD * getPixelColorAt(const int & a_x, const int & a_y) const ;
	int getPixelAt(const int & a_x, const int & a_y) const ;
	RGB_QUAD * getPixelColorAt(const SPoint & p) const ;
	int getPixelAt(const SPoint & p) const ;
	RGB_QUAD * getColor(const int & a_i) const ;
	short getBitDepth() const ;
	long getColorCount() const ;
	void debugPrint() const ;
	int save(const char * a_filename) const;
	~BitMaP();

	void setPixelAt(const SPoint & p, const int & a_colorIndex);
	void setArea(const SRect & area, const int & a_colorIndex);
	void replacePixels(const SRect & area, const int & a_search, const int & a_replace);
	void swapColorIndex(const int & a_index1, const int & a_index2);
	int countOccurances(const int & a_colorIndex);
	bool putUsedColorsInFront(int & a_start, int & a_end);
	int putUsedColorsInFront();
	int orderIndex();
	int getColorIndex(const RGB_QUAD & a_color);

	bool isBMP()
	{
		return getData()[0] == 'B'
			&& getData()[1] == 'M'
			&& getData()[6] == 0
			&& getData()[7] == 0
			&& getData()[8] == 0
			&& getData()[9] == 0;
	}
};

#endif
